#include <dretve.h>
#include <pozivi_jezgre.h>
#include <jezgra/tipovi.h>

//stvori novu dretvu koja ce radit funkciju "poc_funkc(param)"
int stvori_dretvu_pr (void (*poc_funkc)(void *), void *param, void *stog,
			int prio, int rasp)
{
	struct {
		void (*poc_funkc)(void *);	//pocetna funckija dreve
		void *param;			//parametar za stog
		void *stog;			//pocetni stog
		int prio;			//prioritet
		int rasp;			//koji rasporedjivac? FIFO, RR
	} p;

	p.poc_funkc = poc_funkc;
	p.param = param;
	p.stog = stog;
	p.prio = prio;
	p.rasp = rasp;
	
	return J_FUNKCIJA(STVORI_DRETVU, &p);
}

//stvori novu dretvu koja ce radit funkciju "poc_funkc(param)"
int stvori_dretvu (void (*poc_funkc)(void *), void *param)
{
	return stvori_dretvu_pr(poc_funkc, param, NULL,	PRIO_POCETNI, RASP_PRP);
}

//stvori novi proces
int stvori_proces_pr (  void (*poc_funkc) (void *), void *param, void *stog,
			int prio, int rasp, bool priv, void *pocetna_adresa,
			uint velicina )
{
	struct {
		void (*poc_funkc) (void *);	//pocetna funckija dreve
		void *param;			//parametar za stog
		void *stog;			//pocetni stog
		int prio;			//prioritet
		int rasp;			//koji rasporedjivac? FIFO, RR

		bool u_jezgri;
		void *pocetna_adresa;
		uint32 velicina;
	} p;

	p.poc_funkc = poc_funkc;
	//kada bi radio s absolutnim adresama trebalo bi ovu adresu zbrojit
	//s pocetkom adresnog prostora programa

	p.param = param;
	p.stog = stog;
	p.prio = prio;
	p.rasp = rasp;
	
	p.u_jezgri = priv;
	p.pocetna_adresa = pocetna_adresa;
	p.velicina = velicina;
	//staviti 0xffffffff - ako se zeli da ostane u abs. adresama
	//i adresira cijeli adresni prostor, uz pocetna_adresa = 0!

	return J_FUNKCIJA ( STVORI_PROCES, &p );
}

//stvori novi proces
int stvori_proces ( void (*poc_funkc)(void *), void *param )
{
	return stvori_proces_pr ( poc_funkc, param, NULL, PRIO_POCETNI,
				  RASP_PRP, NEISTINA, NULL, 0 );
}

int zavrsi_proces ()
{
	return J_FUNKCIJA ( ZAVRSI_PROCES, NULL );
}

int prekini_proces ( int id_procesa )
{
	return J_FUNKCIJA ( ZAVRSI_PROCES, &id_procesa );
}

//propusta procesor iducoj dretvi, ako takva postoji
//vraca 0, ako je odstupila, 1 ako nije (npr. nema drugih dretvi)
int dretva_odstupi ()
{
	return J_FUNKCIJA(DRETVA_ODSTUPI, NULL);
}

//poziva se kada dretva zeli prije zavrsiti
int zavrsi_dretvu ()
{
	return J_FUNKCIJA(DRETVA_ZAVRSETAK, NULL);
}

//vrati 'id' trenutne dretve
int id_dretve ()
{
	return J_FUNKCIJA(ID_DRETVE, NULL);
}

//prioriteti
//dohvati prioritet dretve s "id", ili pozivajuce, ako je id = 0
int dohvati_prioritet (int id)
{
	return J_FUNKCIJA(DOHVATI_PRIORITET, &id);
}

int postavi_prioritet (int prio)
{
	return J_FUNKCIJA(POSTAVI_PRIORITET, &prio);
}

int cekaj_kraj_dretve (int id)
{
	return J_FUNKCIJA(CEKAJ_KRAJ_DRETVE, &id);
}


//sinkronizacija: semafor/monitor/red uvjeta
int dohvati_sinkro (int tip, int sort, int zast, int pocvr)
{
	struct {
		uint8	tip;	//tip reda
		uint8	sort;	//nacin sortiranja reda
		uint16	zast;	//zastavice
		uint	poc_vr;	//pocetna vrijednost
	} p;

	p.tip = tip;
	p.sort = sort;
	p.zast = zast;
	p.poc_vr = pocvr;

	return J_FUNKCIJA(DOHVATI_SINKRO, &p);
}

int obrisi_sinkro (int id)
{
	return J_FUNKCIJA(OBRISI_SINKRO, &id);
}

int postavi_sinkro (int id, bool sve)
{
	struct {
		int id;		//id reda
		bool sve;	//propusta sve ili samo jednu dretvu?
	} p;
	
	p.id = id;
	p.sve = sve;
	
	return J_FUNKCIJA(PROPUSTI_SINKRO, &p);
}

int cekaj_sinkro (int id_p, uint zast, int id_s, vrijeme_t *koliko)
{
	struct {
		int id_p;
		//primarni id (id reda uvjeta ili semafora ili monitora)

		uint zast;	//zastavice: PROBAJ, DRUGAOP

		int id_s;
		//sekundarni id (ako je primarni red uvjeta ovo je monitor)

		vrijeme_t *koliko;
		//ako je != 0 kaze koliko ce se cekati u blokiranom redu
		//po isteku vremena dretva se odblokira, a povratna je
		//vrijednost -1 (oznaka greske)
	} p;
	int povvr1 = -1, povvr2 = -1;
	
	p.id_p = id_p;
	p.id_s = id_s;
	p.zast = zast;
	p.koliko = koliko;

	//CekajSem ili udji_u_monitor ili uvrsti_u_red_uvjeta
	povvr1 = J_FUNKCIJA(CEKAJ_SINKRO, &p);
	
	//kad dretva dodje do tu, neko ju je oslobodio
	//ako je prije bio 'uvrsti_u_red_uvjeta', sada treba zauzeti monitor
	//(moze i nesto drugo, ali to bas i nema smisla)
	if (povvr1 != -1 && (zast & DRUGAOP)) {
		p.id_p = id_s;
		p.id_s = -1;
		p.koliko = NULL;

		povvr2 = J_FUNKCIJA(CEKAJ_SINKRO, &p);
	}

	if (povvr1 < 0)
		return povvr1;
	else
		return povvr2;
}

/* dio izbacen iz koda jezgre, jer se ne izvodi/nalazi u jezgri */

//stogovi za dretve
int j_stog_dretve[NAJ_DRETVI][VELICINA_STOGA / sizeof(int)];

//pocetna funkcija za sve dretve, iz argumenata se uzima funkcija koju je zadao
//korisnik te se ona poziva;
//kada dodje do kraja, dretva zavrsava - NIJE jezgrina funkcija
void pokreni_dretvu (void (*pocetna_funkcija)(void *), void *param)
{
	//j_ispisi("pocfunc=%x, param=%x\n", pocetna_funkcija, param);
	
	pocetna_funkcija(param);
	
	//oznaci zavrsetak dretve
	J_FUNKCIJA(DRETVA_ZAVRSETAK, NULL);
}

//aktivira se kad nema nista drugo
#include <jezgra/razno.h>
void latentna_dretva (void *param)
{
	while(1) {
		//ispisi("latenta\n");
		j_zaustavi();
	}
}
